package com.pi.shisan.diy.controller;

import com.pi.shisan.common.NumberUtil;
import com.pi.shisan.component.util.ComponentThread;
import com.pi.shisan.diy.Run;
import com.pi.shisan.service.schedule.LoadingComponent;
import com.pi.shisan.service.util.AppUtil;
import com.pi.shisan.service.util.ComponentManager;
import com.pi.shisan.service.util.DspProcessorCallBackFactory;
import com.pi.shisan.service.util.FastFFT;
import com.pi.shisan.util.DefaultFont8x8;
import com.pi.shisan.util.spipoint.MergedSpi;
import com.pi.shisan.util.spipoint.MultipleFlushSpi;
import com.pi.shisan.util.spipoint.MultipleXyToSpiConverter;
import de.quippy.javamod.mixer.dsp.DspProcessorCallBack;
import javafx.application.Platform;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.paint.Color;
import org.springframework.boot.SpringApplication;

import java.net.URL;
import java.util.LinkedList;
import java.util.ResourceBundle;

public class IndexController implements Initializable {

    @FXML
    private Canvas canvas;

    private static ComponentManager componentManager;

    @Override
    public void initialize(URL location, ResourceBundle resources) {
        //这里为了调平电平显示量提前了的问题，如果不需要，可以将此处代码删除
        DspProcessorCallBackFactory.setDspProcessor(musicEffectComponents -> new DspProcessorCallBack() {
            private FastFFT fft = new FastFFT(2048);
            /**
             * 用于延迟绘制，因为在win11上测试，发生电平比音频要早半拍的情况
             */
            private LinkedList<PointData> queue = new LinkedList<>();
            @Override
            public void currentSampleChanged(float[] leftSample, float[] rightSample) {
                if (musicEffectComponents != null) {
                    PointData pointData = new PointData();
                    if (leftSample != null) {
                        fft.calculate(leftSample);
                        pointData.setLeft(fft.getMax());
                    }
                    if (rightSample != null) {
                        fft.calculate(rightSample);
                        pointData.setRight(fft.getMax());
                    }
                    long current;
                    pointData.setTimestamp(current = System.currentTimeMillis());
                    queue.add(pointData);
                    while (true) {
                        try {
                            pointData = queue.getFirst();
                        } catch (Exception e) {
                            break;
                        }
                        if (current - pointData.getTimestamp() < 310 /*视自己电脑情况而定，如果是提前量，则为正数，可延迟显示*/) {
                            break;
                        }
                        queue.pollFirst();
                        if (musicEffectComponents.getLeftMusicEffectComponent() != null) {
                            musicEffectComponents.getLeftMusicEffectComponent().setVal(pointData.getLeft());
                        }
                        if (musicEffectComponents.getRightMusicEffectComponent() != null) {
                            musicEffectComponents.getRightMusicEffectComponent().setVal(pointData.getRight());
                        }
                    }
                }
            }
        });
        Run.getStage().setOnCloseRequest(e->{
            SpringApplication.exit(AppUtil.getApplicationContext());
        });
        MultipleFlushSpiAsCanvas spi = new MultipleFlushSpiAsCanvas(new MergedSpi(4, 3), canvas);
        componentManager = new ComponentManager(spi);
        LoadingComponent.showOnce(spi);
        new Thread(()->{
            SpringApplication.run(Run.class);
        }).start();
    }

    public static ComponentManager getComponentManager() {
        return componentManager;
    }

    /**
     * 不支持rotate180，所以不要开启这个功能
     */
    static class MultipleFlushSpiAsCanvas extends MultipleFlushSpi {

        private GraphicsContext graphicsContext;
        private Canvas canvas;

        public MultipleFlushSpiAsCanvas(MultipleXyToSpiConverter multipleXyToSpiConverter, Canvas canvas) {
            super(multipleXyToSpiConverter);
            this.canvas = canvas;
            this.graphicsContext = canvas.getGraphicsContext2D();
        }

        @Override
        public void lightLevel(int level) {
            //这里就不做实现了，没意义
        }

        @Override
        public void flushData() {
            int w = multipleXyToSpiConverter.getW();
            int h = multipleXyToSpiConverter.getH();
            int pointSize = 10;
            int gap = 2;
            int width = w * 8 * pointSize + (w * 8 * gap) - gap;
            int height = h * 8 * pointSize + (h * 8 * gap) - gap;
            ComponentThread.execute(()->{
                long[] points = toSpiPoints();
                Platform.runLater(()->{
                    canvas.setWidth(width);
                    canvas.setHeight(height);
                    graphicsContext.setFill(Color.WHITE);
                    graphicsContext.fillRect(0,0,width,height);
                    graphicsContext.setFill(Color.BLACK);
                    int startX = 0;
                    int startY = 0;
                    for (int i = 0; i < w * h; i++) {
                        if (i > 0 && i % w == 0) {
                            startX = 0;
                            startY += 8 * pointSize + gap * 7 + (startY > 0 ? 1 : startY);
                        }
                        for (int y = 0; y < 8; y++) {
                            for (int x = 0; x < 8; x++) {
                                int vx = x * pointSize + (gap + gap * (x - 1)) + startX;
                                int vy = y * pointSize + (gap + gap * (y - 1)) + startY;
                                graphicsContext.rect(vx, vy, pointSize,pointSize);
                            }
                        }
                        startX += 8 * pointSize + gap * 7 + (startX > 0 ? 1 : startX);
                    }
                    graphicsContext.stroke();
                    graphicsContext.beginPath();
                    startX = 0;
                    startY = 0;
                    for (int i = 0; i < points.length; i++) {
                        if (i > 0 && i % w == 0) {
                            startX = 0;
                            startY += 8 * pointSize + gap * 7 + (startY > 0 ? 1 : startY);
                        }
                        int[] xys = DefaultFont8x8.getPointsAsXy(points[i]);
                        if (xys != null) {
                            for (int k = 0; k < xys.length; k++) {
                                int x = NumberUtil.toX(xys[k]);
                                int y = NumberUtil.toY(xys[k]);
                                x = x * pointSize + (gap + gap * (x - 1)) + startX;
                                y = y * pointSize + (gap + gap * (y - 1)) + startY;
                                graphicsContext.fillRect(x, y, pointSize,pointSize);
                            }
                        }
                        startX += 8 * pointSize + gap * 7 + (startX > 0 ? 1 : startX);
                    }
                    graphicsContext.closePath();
                });
            });
        }

        @Override
        public void close() {
            multipleXyToSpiConverter.clear();
        }
    }

    /**
     * 处理延迟逻辑的一种方式
     */
    public static class PointData {
        private long timestamp;
        private float left;
        private float right;

        public PointData() {
        }

        public long getTimestamp() {
            return timestamp;
        }

        public void setTimestamp(long timestamp) {
            this.timestamp = timestamp;
        }

        public float getLeft() {
            return left;
        }

        public void setLeft(float left) {
            this.left = left;
        }

        public float getRight() {
            return right;
        }

        public void setRight(float right) {
            this.right = right;
        }
    }
}
